#include "lolevel.h"
#include "platform.h"
#include "core.h"
#include "keyboard.h"
#include "math.h"
#include "stdlib.h"
#include "conf.h"

#define USE_FILE_COUNTER_FOR_EXP_COUNTING

#define SS_SIZE (sizeof(shutter_speeds_table)/sizeof(shutter_speeds_table[0]))
#define SSID_MIN (shutter_speeds_table[0].id)
#define SSID_MAX (shutter_speeds_table[SS_SIZE-1].id)

#define AS_SIZE (sizeof(aperture_sizes_table)/sizeof(aperture_sizes_table[0]))
#define ASID_MIN (aperture_sizes_table[0].id)
#define ASID_MAX (aperture_sizes_table[AS_SIZE-1].id)

#define AV96_MIN (aperture_sizes_table[0].prop_id)
#define AV96_MAX (aperture_sizes_table[AS_SIZE-1].prop_id)

#define ISO_SIZE (sizeof(iso_table)/sizeof(iso_table[0]))
#define ISO_MIN (iso_table[0].id)
#define ISO_MAX (iso_table[ISO_SIZE-1].id)
#define ISO_MIN_VALUE (iso_table[1-iso_table[0].id].prop_id)

static const unsigned MODESCNT=(sizeof(modemap)/sizeof(modemap[0]));

/*define PROPCASE_CONT_MODE_SHOOT_COUNT 		218*/
static short iso_market_base=0;
//static short iso_base=0;
static short sv96_base=0;
static short svm96_base=0;
static short sv96_base_tmp=0;
static const double sqrt2=1.4142135623731;//square root from 2 
static const double log_2=0.6931471805599;//natural logarithm of 2
static const double k=12.5;//K is the reflected-light meter calibration constant 
static const short koef[] = {0, 1,10,100,1000};
static const float shutter_koef[] = {0, 0.00001, 0.0001,0.001,0.01,0.1,1,10,100,1000};
static const char * expo_shift[] = { "Off", "1/3Ev","2/3Ev", "1Ev", "1 1/3Ev", "1 2/3Ev", "2Ev", "2 1/3Ev", "2 2/3Ev", "3Ev", "3 1/3Ev", "3 2/3Ev", "4Ev"};

static const char * expo_type[] = { "+/-", "-","+"};

static PHOTO_PARAM photo_param_put_off;

static short *min_av96_zoom_point_tbl = NULL;


//***********************
/*

static char debug_str[60];

void debug_char(char * deb_str)
{
 short debug_str_length=strlen(debug_str);
 if	(debug_str_length>50) strcpy(debug_str, "");
 sprintf(debug_str+debug_str_length, "%s", deb_str);
}

void debug_init()
{
 strcpy(debug_str, "");
}


void debug_int(int deb_str)
{
 short debug_str_length=strlen(debug_str);
 if	(debug_str_length>50) strcpy(debug_str, "");
 sprintf(debug_str+debug_str_length, "%d", deb_str);
}


void debug(char * deb_str, int deb_int)
{
 short debug_str_length=strlen(debug_str);
 if	(debug_str_length>50) strcpy(debug_str, "");
 sprintf(debug_str+debug_str_length, "%s", deb_str);
 sprintf(debug_str+strlen(debug_str), "%d", deb_int);
}

char * get_debug()
{
 return debug_str;
}
*/
//***********************

int shooting_get_user_tv_id()
{
#if CAM_HAS_USER_TV_MODES 
    short tvv;
    long i;
    _GetPropertyCase(PROPCASE_USER_TV, &tvv, sizeof(tvv));
    for (i=0;i<SS_SIZE;i++){
	if (shutter_speeds_table[i].prop_id == tvv)
	    return shutter_speeds_table[i].id;
    }
#endif        
    return 0;
}

short shooting_get_is_mode()
{
    short ism = 0;
    _GetPropertyCase(PROPCASE_IS_MODE, &ism, sizeof(ism));
    return ism;
}


const ShutterSpeed *shooting_get_tv_line()
{
    short tvv;
    long i;
    _GetPropertyCase(PROPCASE_USER_TV, &tvv, sizeof(tvv));
    for (i=0;i<SS_SIZE;i++){
	   if (shutter_speeds_table[i].prop_id == tvv)
	    return &shutter_speeds_table[i];
    }
    return 0;
}

void shooting_set_user_tv_by_id(int v)
{
#if CAM_HAS_USER_TV_MODES
if ((mode_get()&MODE_MASK) != MODE_PLAY){
    long i;
//    if ((v<SSID_MIN) || (v>SSID_MAX))
//	return;
 for (i=0;i<SS_SIZE;i++){
	if (shutter_speeds_table[i].id == v){
	    short vv = shutter_speeds_table[i].prop_id;
	    _SetPropertyCase(PROPCASE_USER_TV, &vv, sizeof(vv));
	    //_SetPropertyCase(PROPCASE_TV, &vv, sizeof(vv));
	    return;
	 }
 }
}
#endif 
}
void shooting_set_prop(int id, int v)
{
   short vv = v;
   _SetPropertyCase(id, &vv, sizeof(vv));
   return;
}

int shooting_get_prop(int id)
{
    short vv;
    _GetPropertyCase(id, &vv, sizeof(vv));
    return vv;
}

short shooting_get_canon_iso_mode()
{
    short isom;
    _GetPropertyCase(PROPCASE_ISO_MODE, &isom, sizeof(isom));
     return isom;
}


int shooting_get_iso_mode()
{
    short isov;
    long i;
    _GetPropertyCase(PROPCASE_ISO_MODE, &isov, sizeof(isov));
    for (i=0;i<ISO_SIZE;i++){
			if (iso_table[i].prop_id == isov)
	   		 return iso_table[i].id;
    }
    return 0;
}

void shooting_set_user_tv_by_id_rel(int v)
{
#if CAM_HAS_USER_TV_MODES
if ((mode_get()&MODE_MASK) != MODE_PLAY){
    int cv = shooting_get_user_tv_id();
    shooting_set_user_tv_by_id(cv+v);
}
#endif    
}

int shooting_get_user_av_id()
{
#if CAM_HAS_IRIS_DIAPHRAGM
    short avv;
    long i;
    _GetPropertyCase(PROPCASE_USER_AV, &avv, sizeof(avv));
    for (i=0;i<AS_SIZE;i++){
			if (aperture_sizes_table[i].prop_id == avv)
	   		 return aperture_sizes_table[i].id;
    }
#endif    
    return 0;
}

short shooting_get_real_aperture() {
//#if !CAM_HAS_IRIS_DIAPHRAGM
//    return shooting_get_min_real_aperture();
//#else
//I hope that GetCurrentAvValue is correct for ixus70_sd1000 ixus700_sd500 now
    return shooting_get_aperture_from_av96(_GetCurrentAvValue());
//#endif
}

short shooting_get_aperture_from_av96(short av96) {
	if (av96) return (short)((pow(sqrt2, ((double)av96)/96.0))*100.0);
	else return -1;
}

short shooting_get_min_real_aperture() {
	 short av96;
	_GetPropertyCase(PROPCASE_MIN_AV, &av96, sizeof(av96));
	if (av96) return shooting_get_aperture_from_av96(av96);
	else return shooting_get_real_aperture();
}

short shooting_get_iso_from_sv96(short sv96)
{
    return (short)(pow(2, (((double) sv96+168.0)/96.0)));
}

short shooting_get_iso_real()
{
    short sv;
    _GetPropertyCase(PROPCASE_SV, &sv, sizeof(sv));
    if (sv == 0) { 
     return 0;
    }
    return shooting_get_iso_from_sv96(sv);
}

short shooting_get_svm96()
{
    short  sv;
     _GetPropertyCase(PROPCASE_SV_MARKET, &sv, sizeof(sv));
     return sv;
}

short shooting_get_sv96()
{
    short  sv;
     _GetPropertyCase(PROPCASE_SV, &sv, sizeof(sv));
     return sv;
}

short shooting_get_base_sv96()
{
   short dsv,sv;
   if (shooting_get_canon_iso_mode()<50) { 	
       _GetPropertyCase(PROPCASE_DELTA_SV, &dsv, sizeof(dsv));
       _GetPropertyCase(PROPCASE_SV, &sv, sizeof(sv));
       sv96_base=(sv-dsv);
   }
   return sv96_base;
}

short shooting_get_sv96_from_iso(short iso)
{
  if  (iso>0) 
    return (short)(log(pow(2.0,(-7.0/4.0))*(double)(iso))*96.0/(log_2));
  return 0;  
}

short shooting_get_svm96_from_iso(short iso)
{
   if  (iso>0) return (short)(log((double)(iso)*32.0/100.0)*96.0/(log_2));
   return 0;   
}  

short shooting_get_iso_market_from_svm96(short svm96)
{
	if (svm96>0 )
		return (short)((double)pow(2, (((double)svm96)/96.0))*100.0/32.0);
	return 0;	
}

short shooting_get_iso_market_base()
{
//if ((iso_market_base==0) && (shooting_get_iso_mode() <= 0)) {
//	 iso_market_base=(short)shooting_get_iso_market_from_svm96(shooting_get_svm96());
// }
 //return iso_market_base;
  if (iso_market_base==0) {
      if (ISO_MIN_VALUE==50) iso_market_base=50;
      else iso_market_base=100;
     }
  return iso_market_base; 	
}

short shooting_get_svm96_base()
{
	if (svm96_base==0) svm96_base=shooting_get_svm96_from_iso(shooting_get_iso_market_base());
	return svm96_base;
}

short shooting_get_iso_base()
{
	sv96_base=shooting_get_base_sv96();
	if (sv96_base!=0) return shooting_get_iso_from_sv96(sv96_base);
	else return 0;
}

// AUTOISO:EXIF
short shooting_get_iso_market()
{
    //double koef;
    short iso_mode=shooting_get_canon_iso_mode();
    if (iso_mode < 50) 
     {
      short iso_b=shooting_get_iso_base();
      if (iso_b) return (short)((shooting_get_iso_market_base()*shooting_get_iso_real())/iso_b);
     }
    return iso_mode;
}

void shooting_set_sv96(short sv96, short is_now){
  short dsv96=0, iso_mode=shooting_get_canon_iso_mode(); 	
if ((mode_get()&MODE_MASK) != MODE_PLAY){
  if (is_now)  {
    if (iso_mode<50) dsv96 =sv96-shooting_get_base_sv96();
    else if (sv96_base) dsv96=sv96-sv96_base;
	else if (sv96_base_tmp) dsv96=sv96-sv96_base_tmp;  
	else
	 { 
	 sv96_base_tmp= (short)((shooting_get_svm96_base()*shooting_get_sv96())/shooting_get_svm96());   
	 dsv96=sv96-sv96_base_tmp;
	 }	 
    while ((shooting_is_flash_ready()!=1) || (focus_busy));
    short svm96_base =shooting_get_svm96_base();
    if (iso_mode>=50) shooting_set_iso_mode(0);
    _SetPropertyCase(PROPCASE_SV_MARKET, &svm96_base, sizeof(svm96_base));
    _SetPropertyCase(PROPCASE_SV, &sv96, sizeof(sv96));
    _SetPropertyCase(PROPCASE_DELTA_SV, &dsv96, sizeof(dsv96));
  }
  else   photo_param_put_off.sv96=sv96;
}
}

short shooting_get_bv96()
{
    short bv = 0;
    _GetPropertyCase(PROPCASE_BV, &bv, sizeof(bv));
    return bv;
}

short shooting_get_canon_overexposure_value()
{
    short bv = 0;
    _GetPropertyCase(PROPCASE_OVEREXPOSURE, &bv, sizeof(bv));
    return bv;
}


short shooting_get_flash_mode()
{
    short fm = 0;
    _GetPropertyCase(PROPCASE_FLASH_MODE, &fm, sizeof(fm));
    return fm;
}

int shooting_get_luminance()// http://en.wikipedia.org/wiki/APEX_system
{
    short bv = shooting_get_bv96();
    int b=(int)(100*k*pow(2.0,((double)(bv-168)/96.0)));
    return b;
}

int shooting_get_exif_subject_dist()
{
    int sd = 0;
    _GetPropertyCase(PROPCASE_SUBJECT_DIST1, &sd, sizeof(sd));
    return sd;
}

int shooting_get_lens_to_focal_plane_width()
{
	return (int)(lens_get_focus_pos()-lens_get_focus_pos_from_lens());
}

short shooting_get_aperture_from_av96_1e3(short av96) {
	if (av96) return (short)(pow(sqrt2, (((double)av96)/96.0))*1000.0 + 0.5);
	else return -1;
}

int shooting_get_hyperfocal_distance_1e3_f2(int av_1e3, int fl)
{
  if ((av_1e3>0) && (fl>0) && (circle_of_confusion>0)) 
    return (((fl*fl)/(av_1e3*circle_of_confusion)*2000)+2*fl+1)/2;
  else return (-1);
}

int shooting_get_hyperfocal_distance_1e3_f(int av, int fl)
{
  if ((av>0) && (fl>0) && (circle_of_confusion>0)) 
    return (((fl*fl)/(av*circle_of_confusion)*200)+2*fl+1)/2;
  else return (-1);
}

int shooting_get_near_limit_f(int s, int av, int fl)
{
  int h_1e3 = shooting_get_hyperfocal_distance_1e3_f(av, fl);
  int m = ((h_1e3 - fl)+500)/1000*s;
  int v = ((h_1e3 + 1000*s - 2*fl)+500)/1000;
  if ((m>0) && (v>0)) return ((2*m/v+1)/2);
  else return (-1);
}

int shooting_get_far_limit_f(int s, int av, int fl)
{
  if (s<MAX_DIST) {
    int h_1e3 = shooting_get_hyperfocal_distance_1e3_f(av, fl);
    int m = ((h_1e3 - fl)+500)/1000*s;
    int v = ((h_1e3 - 1000*s)+500)/1000;
    if ((m>0) && (v>0)) return ((2*m/v+1)/2);
    else return (-1);
  } else return (-1);
}



short shooting_get_tv96_from_shutter_speed(float t)
{
  if (t>0) return (short) (96.0*log(1.0/t)/log_2);  
  else return (-10000);
}

float shooting_get_shutter_speed_from_tv96(short tv)
{
  return  pow(2,(float)((-1)*tv)/96.0 );  
}

short shooting_get_tv96()
{
    short tv96;
    _GetPropertyCase(PROPCASE_TV, &tv96, sizeof(tv96));
    return tv96;
}

short shooting_get_user_tv96()
{
#if CAM_HAS_USER_TV_MODES
    short tv;
    _GetPropertyCase(PROPCASE_USER_TV, &tv, sizeof(tv));
    return tv;
#else       
    return 0;
#endif    
}

void shooting_set_user_tv96(short v)
{
#if CAM_HAS_USER_TV_MODES
if ((mode_get()&MODE_MASK) != MODE_PLAY){
long i;
//    if ((v<SSID_MIN) || (v>SSID_MAX))
//	return;
 for (i=0;i<SS_SIZE;i++){
  	if (shutter_speeds_table[i].prop_id == v){
  		_SetPropertyCase(PROPCASE_USER_TV, &v, sizeof(v));
  		//_SetPropertyCase(PROPCASE_TV, &v, sizeof(v));
	    return;
	  }
  }
}
#endif  
}

void shooting_set_tv96(short v, short is_now)
{
 long i;
//    if ((v<SSID_MIN) || (v>SSID_MAX))
//	return;
if ((mode_get()&MODE_MASK) != MODE_PLAY){
 for (i=0;i<SS_SIZE;i++){
  	if (shutter_speeds_table[i].prop_id == v){
       shooting_set_tv96_direct(v, is_now);
       return;
     }
  }
}
}

void shooting_set_tv96_direct(short v, short is_now)
{
if ((mode_get()&MODE_MASK) != MODE_PLAY){
   	if(is_now) {
	   _SetPropertyCase(PROPCASE_TV, &v, sizeof(v));
   	}
   	else photo_param_put_off.tv96=v; 
}
}


void shooting_set_shutter_speed(float t, short is_now)
{
	if (t>0) shooting_set_tv96_direct((short) 96.0*log(1/t)/log_2, is_now);  
}

void shooting_set_shutter_speed_ubasic(int t, short is_now)
{
if ((mode_get()&MODE_MASK) != MODE_PLAY){
	if (t>0) shooting_set_tv96_direct((short) (96.0*log(100000.0/(double)t)/log_2), is_now);  
}
}

short shooting_get_av96()
{
    short av;
    _GetPropertyCase(PROPCASE_AV, &av, sizeof(av));
    return av;
}

short shooting_get_aperture_sizes_table_size()
{
    return AS_SIZE;
}


short shooting_get_aperture_sizes_table_prop_id(short i)
{
    return aperture_sizes_table[i].prop_id;
}

short shooting_get_max_aperture_sizes_table_prop_id()
{
    return AV96_MAX;
}



short shooting_get_av_prop_id()
{
    short av;
    _GetPropertyCase(PROPCASE_AV, &av, sizeof(av));
    return av;
}



short shooting_get_user_av96()
{
#if CAM_HAS_IRIS_DIAPHRAGM
    short av;
    _GetPropertyCase(PROPCASE_USER_AV, &av, sizeof(av));
    return av;
#else     
    return 0;
#endif
}


void shooting_set_av96(short v, short is_now)
{
#if CAM_HAS_IRIS_DIAPHRAGM	
if ((mode_get()&MODE_MASK) != MODE_PLAY){
 long i;
//    if ((v<ASID_MIN) || (v>ASID_MAX))
//	return;
 for (i=0;i<AS_SIZE;i++){
	if (aperture_sizes_table[i].prop_id == v){
	   shooting_set_av96_direct(v, is_now);
	   return;
	}
  }
}
#endif  
}

void shooting_set_nd_filter_state(short v, short is_now)
{
#if CAM_HAS_ND_FILTER
if ((mode_get()&MODE_MASK) != MODE_PLAY){
	if (is_now) {
	 if (v==1) _PutInNdFilter();
	 else if (v==2) _PutOutNdFilter();
	}
	else photo_param_put_off.nd_filter=v;
}
#endif	
}



void shooting_set_av96_direct(short v, short is_now)
{  
#if CAM_HAS_IRIS_DIAPHRAGM
if ((mode_get()&MODE_MASK) != MODE_PLAY){
 if(is_now) {
   _SetPropertyCase(PROPCASE_AV, &v, sizeof(v));
 }
 else photo_param_put_off.av96=v;
}
#endif
}


void shooting_set_user_av96(short v)
{
#if CAM_HAS_IRIS_DIAPHRAGM
    long i;
if ((mode_get()&MODE_MASK) != MODE_PLAY){
//    if ((v<ASID_MIN) || (v>ASID_MAX))
//	return;

 for (i=0;i<AS_SIZE;i++){
	if (aperture_sizes_table[i].prop_id == v){
		  _SetPropertyCase(PROPCASE_USER_AV, &v, sizeof(v));
		  //_SetPropertyCase(PROPCASE_AV, &v, sizeof(v));
	    return;
	}
 }
}
#endif		   
}

short shooting_get_drive_mode()
{
    short m;
// reyalp - this is related to http://chdk.setepontos.com/index.php/topic,3994.405.html
// TODO
#if defined (CAMERA_sx200is) || \
        defined (CAMERA_g11) || \
        defined (CAMERA_ixus100_sd780) || \
        defined (CAMERA_a480) || \
        defined (CAMERA_a495) || \
        defined (CAMERA_s90) || \
        defined (CAMERA_sx20) || \
        defined (CAMERA_sx120is) || \
        defined (CAMERA_d10) || \
        defined (CAMERA_s95)
   short n;
   // unlike other cameras, sx200 does set PROPCASE_DRIVE_MODE when in custom timer mode
   // SX 200 IS 0,1,2,3,4=Off, 2 Second, Custom, Face Detection
   _GetPropertyCase(PROPCASE_TIMER_MODE, &n, sizeof(n));
   // note we return this only in custom mode.
   // Other cameras would return 3 if any timer mode is set (?) even if it doesn't do multiple exposures
   // note that face detect does multiple exposure
   if(n==3){
      return n;
   }
#endif

    _GetPropertyCase(PROPCASE_DRIVE_MODE, &m, sizeof(m));
    return m;
}

// TODO this should probably use MODE_IS_VIDEO
short shooting_can_focus()
{
#if !CAM_CAN_SD_OVER_NOT_IN_MF && CAM_CAN_SD_OVERRIDE
 int m=mode_get()&MODE_SHOOTING_MASK;
 int mode_video=((m==MODE_VIDEO_STD) || 
			    (m==MODE_VIDEO_SPEED) ||  
			    (m==MODE_VIDEO_COMPACT) ||
			    (m==MODE_VIDEO_MY_COLORS) || 
			    (m==MODE_VIDEO_TIME_LAPSE) ||
			    (m==MODE_VIDEO_COLOR_ACCENT));
  return (shooting_get_focus_mode() || mode_video);
#elif !CAM_CAN_SD_OVERRIDE
 int m=mode_get()&MODE_SHOOTING_MASK;
 int mode_video=((m==MODE_VIDEO_STD) || 
			    (m==MODE_VIDEO_SPEED) ||  
			    (m==MODE_VIDEO_COMPACT) ||
			    (m==MODE_VIDEO_MY_COLORS) || 
    	        (m==MODE_VIDEO_TIME_LAPSE) ||
			    (m==MODE_VIDEO_COLOR_ACCENT));
  return mode_video;
#elif defined (CAMERA_ixus800_sd700)                				   
 int m=mode_get()&MODE_SHOOTING_MASK;
// TODO whats the reason for this ?!?
  return (shooting_get_zoom()<8) && (m!=MODE_AUTO) && (m!=MODE_SCN_UNDERWATER);
#else 
  return 1;  
#endif 			  
}

short shooting_get_common_focus_mode()
{
#if !CAM_HAS_MANUAL_FOCUS && CAM_CAN_SD_OVERRIDE
  return shooting_get_subject_distance_override_koef();
#elif !CAM_CAN_SD_OVERRIDE
  return 0;
#else 
  return shooting_get_focus_mode();
#endif 			  
}

short shooting_get_focus_mode()
{
  short m;
  _GetPropertyCase(PROPCASE_FOCUS_MODE, &m, sizeof(m));
  return m;
}

short shooting_get_real_focus_mode()
{
  short f=shooting_get_focus_mode();
  short m;
  _GetPropertyCase(PROPCASE_REAL_FOCUS_MODE, &m, sizeof(m));
  if (f==0 && m!=0) f=(m==1)?4:m;
  return f;
}

short shooting_get_focus_state()
{
  if (shooting_get_focus_mode()==1) return -1;
  int m;
  _GetPropertyCase(PROPCASE_FOCUS_STATE, &m, sizeof(m));
  return (short) m;
}
 
short shooting_get_focus_ok()
{
  return ((shooting_get_focus_state()!=0) && shooting_in_progress());
}

/*
short shooting_get_continuous_mode_shoot_count()
{
    short c;
    _GetPropertyCase(PROPCASE_CONT_MODE_SHOOT_COUNT, &c, sizeof(c));
    return c;
}
*/


void shooting_set_user_av_by_id(int v)
{
#if CAM_HAS_IRIS_DIAPHRAGM
long i;
if ((mode_get()&MODE_MASK) != MODE_PLAY){
//    if ((v<ASID_MIN) || (v>ASID_MAX))
//	return;
  for (i=0;i<AS_SIZE;i++){
		if (aperture_sizes_table[i].id == v){
	    short vv = aperture_sizes_table[i].prop_id;
	    _SetPropertyCase(PROPCASE_USER_AV, &vv, sizeof(vv));
	    //_SetPropertyCase(PROPCASE_AV, &vv, sizeof(vv));
	    return;
		}
  }
}
#endif	      
}

void shooting_set_user_av_by_id_rel(int v)
{
#if CAM_HAS_IRIS_DIAPHRAGM
if ((mode_get()&MODE_MASK) != MODE_PLAY){
    int cv = shooting_get_user_av_id();
    shooting_set_user_av_by_id(cv+v);
}
#endif    
}


int shooting_get_day_seconds()
{
    unsigned long t;
    struct tm *ttm;
    t = time(NULL);
    ttm = localtime(&t);
    return ttm->tm_hour * 3600 + ttm->tm_min * 60 + ttm->tm_sec;
}

int shooting_get_tick_count()
{
    return (int)get_tick_count();
}

void shooting_set_iso_mode(int v)
{
 long i;
 for (i=0;i<ISO_SIZE;i++){
	if (iso_table[i].id == v){
	    short vv = iso_table[i].prop_id;
	    _SetPropertyCase(PROPCASE_ISO_MODE, &vv, sizeof(vv));
	    return;
	}
  }
}

int shooting_in_progress()
{
    int t = 0;
    _GetPropertyCase(PROPCASE_SHOOTING, &t, sizeof(&t));
    return t != 0;
}

int shooting_is_flash()
{
 int t = 0;	
 _GetPropertyCase(PROPCASE_IS_FLASH_READY, &t,sizeof(&t));
 return t;
}

int shooting_is_flash_ready()
{
   int t = 0;
/* well, I'm not sure what's exactly is happening here
 * but it works for a610-100e
 */
   // _GetPropertyCase(204, &t, 4);
   // if (t == 3){
   _GetPropertyCase(PROPCASE_FLASH_MODE, &t, sizeof(&t));
   if ((t != 2) && (shooting_in_progress()))
     if (shooting_is_flash()) return _IsStrobeChargeCompleted();
   return 1;
}

long get_file_counter()
{
#ifndef PARAM_FILE_COUNTER
#	error Please define PARAM_FILE_COUNTER in platform`s shooting.c!
#endif
    long v = 0;
    get_parameter_data(PARAM_FILE_COUNTER, &v, 4);
    return v;
}

long get_exposure_counter()
{
#if defined(USE_FILE_COUNTER_FOR_EXP_COUNTING) || !defined(PARAM_EXPOSURE_COUNTER)
    long v = 0;
    get_parameter_data(PARAM_FILE_COUNTER, &v, 4);
    v = ((v>>4)&0x3FFF);
    return v;
#else
    long v = 0;
    get_parameter_data(PARAM_EXPOSURE_COUNTER, &v, 4);
    return v;
#endif
}

short shooting_get_ev_correction1()
{
    short evc1 = 0;
    _GetPropertyCase(PROPCASE_EV_CORRECTION_1, &evc1, sizeof(evc1));
    return evc1;
}


int shooting_get_zoom() {
    return lens_get_zoom_point();
}

void shooting_set_zoom(int v) {
    int dist;
if ((mode_get()&MODE_MASK) != MODE_PLAY)
	{
    //dist = shooting_get_focus();
    lens_set_zoom_point(v);
    //shooting_set_focus(dist, SET_NOW);
  }
}

void shooting_set_zoom_rel(int v) {
    int cv = shooting_get_zoom();
if ((mode_get()&MODE_MASK) != MODE_PLAY){
    shooting_set_zoom(cv+v);
}
}

void shooting_set_zoom_speed(int v) {
if ((mode_get()&MODE_MASK) != MODE_PLAY){
    lens_set_zoom_speed(v);
}
}




// TODO sd990 hack for overrides
// caller must save regs
int captseq_hack_override_active() {
 return 0;
}

void __attribute__((naked,noinline)) shooting_expo_param_override(void){
 asm volatile("STMFD   SP!, {R0-R12,LR}\n");


 asm volatile("LDMFD   SP!, {R0-R12,PC}\n");
}

void unlock_optical_zoom(void){

#if CAM_CAN_UNLOCK_OPTICAL_ZOOM_IN_VIDEO
 if (conf.unlock_optical_zoom_for_video) _UnsetZoomForMovie();
#endif

#if CAM_EV_IN_VIDEO
 set_ev_video_avail(0);
#endif

}


#if CAM_EV_IN_VIDEO

int ev_video_avail;
int ev_video;
int save_tv_video;
int tv_min_video;

int get_ev_video_avail(void){
 return ev_video_avail;
}

void set_ev_video_avail(int x){
 if (ev_video_avail==x) return;
 ev_video_avail=x;
 if (x) {
  ev_video=0;
  _ExpCtrlTool_StopContiAE(0,0);
  _GetPropertyCase(PROPCASE_TV,&save_tv_video,2);
  if ((mode_get()&MODE_SHOOTING_MASK)==MODE_VIDEO_SPEED) tv_min_video=577;  // 1/60
   else tv_min_video=480; //1/30
 }
 else _ExpCtrlTool_StartContiAE(0,0);
}

int get_ev_video(void){
 return ev_video;
}

void set_ev_video(int x){
 short ev, tv;
 if ((x<-4)||(x>4)) return;
 ev=48*x;
 tv=save_tv_video-ev;
 if (tv>=tv_min_video) {
  ev_video=x;
  _SetAE_ShutterSpeed(&tv);
 }
}

#endif

int shooting_mode_canon2chdk(int canonmode) {
	int i;
	for (i=0; i < MODESCNT; i++) {
		if (modemap[i].canonmode == canonmode) 
			return modemap[i].hackmode;
	}
	return 0;
}

int shooting_mode_chdk2canon(int hackmode) {
	int i;
	for (i=0; i < MODESCNT; i++) {
		if (modemap[i].hackmode == hackmode) 
			return modemap[i].canonmode;
	}
	return -1; // 0 is a valid mode on old cameras!
}

int shooting_set_mode_chdk(int mode) {
	int canonmode = shooting_mode_chdk2canon(mode);
	if (canonmode == -1 || !rec_mode_active())
		return 0;
	_SetCurrentCaptureModeType(canonmode);
	// TODO since mode seems to be fully set when this returns,
	// we could check if it worked
	return 1;
}

int shooting_set_mode_canon(int canonmode) {
	if(canonmode == -1 || !rec_mode_active())
		return 0;
	_SetCurrentCaptureModeType(canonmode);
	return 1;
}

// override in platform/<cam>/main.c if playrec_mode is not found or different
int __attribute__((weak)) rec_mode_active(void) {
    return (playrec_mode==2 || playrec_mode==4 || playrec_mode==5);
}

// currently nothing needs to override this, so not weak
int /*__attribute__((weak))*/ mode_get(void) {
    int mode, t=0xFF;

    mode = (rec_mode_active())?MODE_REC:MODE_PLAY;

#ifdef CAM_SWIVEL_SCREEN
    mode |= (screen_opened())?MODE_SCREEN_OPENED:0;
    mode |= (screen_rotated())?MODE_SCREEN_ROTATED:0;
#endif

    _GetPropertyCase(PROPCASE_SHOOTING_MODE, &t, 4);
	mode |= shooting_mode_canon2chdk(t);

    return (mode);
}
